package com.yanqu.road.server.manger.kowloon.battle;

import com.alibaba.fastjson.JSON;
import com.yanqu.road.entity.config.skill.SkillInfo;
import com.yanqu.road.entity.enums.eSkillType;
import com.yanqu.road.entity.enums.eSpecialServerType;
import com.yanqu.road.entity.kowloon.KowloonNpcAttributeData;
import com.yanqu.road.entity.kowloon.KowloonUserData;
import com.yanqu.road.entity.kowloon.battle.KowloonBattleBuffHeroHelper;
import com.yanqu.road.entity.kowloon.battle.KowloonBattleData;
import com.yanqu.road.entity.kowloon.battle.KowloonBattleEnemyData;
import com.yanqu.road.entity.kowloon.battle.KowloonBattleHeroData;
import com.yanqu.road.entity.kowloon.common.KowloonCoord;
import com.yanqu.road.entity.kowloon.common.KowloonRange;
import com.yanqu.road.entity.kowloon.common.Vec2;
import com.yanqu.road.entity.kowloon.config.KowloonMissionRoadConfig;
import com.yanqu.road.entity.kowloon.config.KowloonNpcAttributeConfig;
import com.yanqu.road.entity.kowloon.config.KowloonNpcConfig;
import com.yanqu.road.entity.kowloon.enums.eKowloonBlockType;
import com.yanqu.road.entity.kowloon.enums.eKowloonRouteType;
import com.yanqu.road.entity.kowloon.sanxiao.KowloonBlock;
import com.yanqu.road.entity.kowloon.sanxiao.KowloonChooseHeroData;
import com.yanqu.road.entity.kowloon.sanxiao.KowloonGameData;
import com.yanqu.road.entity.kowloon.sanxiao.KowloonSkill;
import com.yanqu.road.entity.servercenter.ServerInfo;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.model.kowloon.KowloonConfig;
import com.yanqu.road.server.manger.kowloon.battle.helper.KowloonEnemyDeadParam;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.config.Config;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

import static com.yanqu.road.logic.model.kowloon.KowloonConfig.*;

/**
 * 九龙城寨战斗逻辑
 */
public class KowloonBattleLogic {

    protected Logger logger = LogManager.getLogger(KowloonBattleLogic.class.getName());


    /**
     * 随机数种子
     */
    private int randomSeed;


    /**
     * 游戏数据
     */
    private KowloonGameData gameData;

    /**
     * 九龙城寨专属技能
     */
    private Map<Integer, SkillInfo> skillInfoMap = new ConcurrentHashMap<>();

    private KowloonBattleData battleData = null;

    /**
     * 非战斗用随机
     */
    private static RandomHelper randomHelper = new RandomHelper();

    private AtomicLong uniqueId = new AtomicLong(0);

    private KowloonConfig config = null;

    private boolean finish1002FailGuide;

    public KowloonBattleLogic(KowloonUserData userData, ServerInfo serverInfo, SkillInfo moraleSkillInfo, KowloonConfig config) {
        this.config = config;
        this.gameData = userData.getGameData();
        // 第9步 9:挑战第二关直到弹出战斗失败（100533-100534）
        finish1002FailGuide = ((userData.getGuideBit() >> (9 - 1) & 1) == 1);
        // 九龙城寨技能
        this.skillInfoMap = config.getKowloonSkillInfoMap();
        battleData = new KowloonBattleData();
        this.randomSeed = randomHelper.next(1, 10000);
        // 记录创建战斗的随机种子
        battleData.setRandomSeed(randomSeed);
        KowloonMissionRoadConfig missionRoadConfig = config.getKowloonMissionRoadConfig(gameData.getChapterId(), gameData.getSectionId());
        if (missionRoadConfig == null) {
            throw new RuntimeException("关卡配置不存在,关卡id:" + gameData.getChapterId() + "波次:" + gameData.getSectionId());
        }
        // 英雄信息
        for (List<KowloonBlock> blockList : gameData.getBlockList()) {
            for (KowloonBlock block : blockList) {
                if (!eKowloonBlockType.isHero(block.getType())) {
                    continue;
                }
                // 记录下英雄数据
                KowloonBattleHeroData battleHeroData = new KowloonBattleHeroData();
                // 英雄信息,转换成实际的好汉id
                KowloonChooseHeroData chooseHero = gameData.getChooseHero(block.getType());
                if (chooseHero != null) {
                    // 获取下好汉信息
                    battleHeroData.setHeroId(chooseHero.getHeroId());
                    battleHeroData.setLevel(chooseHero.getLevel());
                    battleHeroData.setMergeLevel(block.getLevel());
                    KowloonCoord pos = new KowloonCoord();
                    pos.setCol(block.getX());
                    pos.setRow(block.getY());
                    battleHeroData.setPos(pos);
                    battleHeroData.setProperty(config.calcHeroAttribute(battleHeroData.getHeroId(), battleHeroData.getLevel(), battleHeroData.getMergeLevel()));
                    battleData.getHeroDataList().add(battleHeroData);
                    if (Config.isDebug()) {
                        logger.info("英雄信息:{},位置,x:{},y:{}", battleHeroData.getHeroId(), block.getX(), block.getY());
                    }
                }
            }
        }
        // 摊位血量
        battleData.setHp(gameData.getHp());
        // 所有好汉位置
        Set<Integer> allHeroXPos = getAllHeroXPos(gameData);
        // 特色服加血量需要随机的敌人id
        List<Long> upHpEnemyIdList = new ArrayList<>();
        for (int i = 0; i < missionRoadConfig.getRuffianIdList().size(); i++) {
            int enemyId = missionRoadConfig.getRuffianIdList().get(i);
            if (enemyId == 0) {
                continue;
            }
            KowloonNpcConfig enemyConfig = config.getKowloonEnemyConfig(enemyId);
            if (enemyConfig == null) {
                // 找不到没办法了
                continue;
            }
            // 地痞移动路线
            String[] split = missionRoadConfig.getRuffianWalkRoute().get(i).split("=");
            int yPos = Integer.parseInt(split[0]);
            List<Integer> walkRouteList = StringUtils.stringToIntegerList(split[1], ";");
            // 移动速度比例
            List<Integer> moveRandom = StringUtils.stringToIntegerList(missionRoadConfig.getMoveRandom().get(i), "\\;");
            // 缩放比例
            List<Integer> resourceSizeRandom = StringUtils.stringToIntegerList(missionRoadConfig.getResourceSizeRandom().get(i), "\\;");
            // 出生时间
            Integer bornTime = missionRoadConfig.getRuffianDelayTime().get(i);
            // 血量
            long hp = missionRoadConfig.getRuffianHp().get(i);
            // 生成数量
            Integer genCount = missionRoadConfig.getRuffianNum().get(i);
            // 已生成的敌人位置map
            Map<Integer, Integer> posCnt = new HashMap<>();
            for (int j = 0; j < genCount; j++) {
                // 生成敌人
                // 地痞移动路线
                LinkedList<Integer> routeList = new LinkedList<>();
                for (Integer walkRoute : walkRouteList) {
                    routeList.addLast(walkRoute);
                }
                List<Vec2> posList = new ArrayList<>();
                // 随机一个初始位置
                Vec2 initPos = new Vec2();
                // 是boss
                if (config.getKowloonBossConfig(enemyId) != null && gameData.getBossBirthPosList().size() > 0) {
                    initPos = gameData.getBossBirthPosList().remove(0);
                } else {
                    // 随机一个好汉的位置
                    initPos.setX(randomXPos(allHeroXPos, posCnt));
                    initPos.setY(yPos);
                    // 判断下是不是初始从旁边出来
                    if (routeList.getFirst() == eKowloonRouteType.Route4.getValue()) {
                        // 移除掉先处理了
                        routeList.removeFirst();
                        // 先加入旁边的点
                        Vec2 route4Birth = new Vec2();
                        if (initPos.getX() <= BATTLE_WIDTH_PIXEL / 2) {
                            // 左
                            route4Birth.setX(0 + TILE_SIZE / 2);
                        } else {
                            // 右
                            route4Birth.setX(BATTLE_WIDTH_PIXEL - TILE_SIZE / 2);
                        }
                        route4Birth.setY(yPos);
                        // 加入出生点
                        posList.add(route4Birth);
                    }
                    if (routeList.getFirst() == eKowloonRouteType.Route8.getValue()) {
                        // 路线8开头的路线x轴不跟着好汉走
                        if (initPos.getX() <= BATTLE_WIDTH_PIXEL / 2) {
                            // 左
                            initPos.setX(0 + TILE_SIZE / 2);
                        } else {
                            // 右
                            initPos.setX(BATTLE_WIDTH_PIXEL - TILE_SIZE / 2);
                        }
                    }
                }
                // 路径加入初始位置
                posList.add(initPos);
                KowloonBattleEnemyData enemyData = genEnemy(enemyId, posList, routeList, bornTime, hp, moveRandom, resourceSizeRandom);
                if (i != 0) {
                    upHpEnemyIdList.add(enemyData.getUniqueId());
                }
                if (enemyData != null) {
                    battleData.getEnemyDataList().add(enemyData);
                    if (Config.isDebug()) {
                        logger.info("生成地痞信息:{},位置,x:{},y:{},出现时间:{},行走路线:{}", enemyData.getEnemyId(), initPos.getX(), initPos.getY(), enemyData.getBornTime(), JSON.toJSONString(enemyData.getPath()));
                    }
                }
            }
        }
        // 计算好汉技能加成
        calcHeroBattleAttribute(moraleSkillInfo);
        // 计算敌人技能加成
        calcEnemyBattleAttribute();
        // 特色服敌人处理
        if (serverInfo.getSpecialServer() == eSpecialServerType.Kowloon.getValue()) {
            // 特色服关卡怪物攻击配置（关卡id；地痞或boss攻击值）
            List<Integer> specialAttackParamList = StringUtils.stringToIntegerList(GameConfig.KOWLOON_GUIDE_SPECIAL_ATTACK, ";");
            if (gameData.getChapterId() == specialAttackParamList.get(0)) {
                for (KowloonBattleEnemyData enemyData : battleData.getEnemyDataList()) {
                    enemyData.getAttributeData().setAttack(specialAttackParamList.get(1));
                }
            }
            // 特色服关卡怪物血量配置（关卡id；每波随机n只怪物；怪物血量乘千分比）
            List<Integer> specialHpParamList = StringUtils.stringToIntegerList(GameConfig.KOWLOON_GUIDE_SPECIAL_HP, ";");
            if (gameData.getChapterId() == specialHpParamList.get(0) && !finish1002FailGuide) {
                int handlerCnt = 0;
                Collections.shuffle(upHpEnemyIdList);
                List<Long> upIdList = new ArrayList<>();
                for (Long enemyId : upHpEnemyIdList) {
                    if (handlerCnt >= specialHpParamList.get(1)) {
                        break;
                    }
                    handlerCnt++;
                    upIdList.add(enemyId);
                }
                for (KowloonBattleEnemyData enemyData : battleData.getEnemyDataList()) {
                    if (upIdList.contains(enemyData.getUniqueId())) {
                        enemyData.getAttributeData().setHp(BigDecimal.valueOf(enemyData.getAttributeData().getHp()).multiply(BigDecimal.valueOf(specialHpParamList.get(2))).divide(BigDecimal.valueOf(1000), 0, RoundingMode.DOWN).longValue());
                    }

                }
            }
        }
    }

    public KowloonBattleEnemyData genEnemy(int enemyId, List<Vec2> path, LinkedList<Integer> routeList, Integer bornTime, long hp, List<Integer> moveRandom, List<Integer> resourceSizeRandom) {
        // 生成敌人
        KowloonBattleEnemyData enemyData = new KowloonBattleEnemyData();
        enemyData.setUniqueId(uniqueId.incrementAndGet());
        enemyData.setEnemyId(enemyId);
        if (routeList != null) {
            enemyData.setWalkRouteList(routeList);
        }
        // 路径加入初始位置
        enemyData.getPath().addAll(path);
        // 地痞出生时间
        enemyData.setBornTime(bornTime);
        // 地痞属性
        KowloonNpcConfig enemyConfig = config.getKowloonEnemyConfig(enemyId);
        if (enemyConfig == null) {
            return null;
        }
        KowloonNpcAttributeConfig npcAttribute = enemyConfig.getNpcAttribute();
        KowloonNpcAttributeData attributeData = new KowloonNpcAttributeData();
        // 地痞攻击
        attributeData.setAttack(npcAttribute.getAtk());
        // 地痞血量
        attributeData.setHp(Math.max(1, hp));
        // 移速 每秒移动的像素
        attributeData.setMoveSpeed(BigDecimal.valueOf(npcAttribute.getMoveSpeed()).multiply(BigDecimal.valueOf(randomHelper.next(moveRandom.get(0), moveRandom.get(1) + 1))).divide(BigDecimal.valueOf(1000), 0, RoundingMode.DOWN).intValue());
        // 受击范围
        attributeData.setHitRange(npcAttribute.getHitRange());
        enemyData.setAttributeData(attributeData);
        // 地痞资源缩放
        enemyData.setResourceSize(randomHelper.next(resourceSizeRandom.get(0), resourceSizeRandom.get(1) + 1));
        // buffcd
        enemyData.setBuffCd(npcAttribute.getBuffCd());
        // 判断是否死后爆炸
        List<Integer> deadParamList = npcAttribute.getDeadParamList();
        if (!deadParamList.isEmpty()) {
            // 地痞id， 地痞数量，地痞血量千分比
            long sonHp = BigDecimal.valueOf(hp).multiply(BigDecimal.valueOf(deadParamList.get(2))).divide(BigDecimal.valueOf(1000), 0, RoundingMode.DOWN).longValue();

            // 生成n只
            for (int i = 0; i < deadParamList.get(1); i++) {
                // 随机一个位置
                List<int[]> dirList = new ArrayList<>();
                for (int[] deadDir : DEAD_DIRS) {
                    int newX = (int) (deadDir[0] * TILE_SIZE + enemyData.getPath().getFirst().getX());
                    int newY = (int) (deadDir[0] * TILE_SIZE + enemyData.getPath().getFirst().getY());
                    if (newX < 0 || newY < 0 || newX > BATTLE_WIDTH_PIXEL || newY > BATTLE_HEIGHT_PIXEL) {
                        continue;
                    }
                    dirList.add(deadDir);
                }
                int[] dir = dirList.get(randomHelper.next(0, dirList.size()));
                Vec2 vec2 = new Vec2(dir[0] * TILE_SIZE, dir[1] * TILE_SIZE);
                KowloonBattleEnemyData sonEnemyData = genEnemy(deadParamList.get(0), Collections.singletonList(vec2), null, 0, sonHp, moveRandom, resourceSizeRandom);
                if (sonEnemyData != null) {
                    enemyData.getDeadBornEnemyList().add(sonEnemyData);
                }
            }
        }
        // 计算移动路线
        calcRoute(enemyData);
        return enemyData;
    }

    public static  Set<Integer> getAllHeroXPos(KowloonGameData gameData) {
        Set<Integer> set = new HashSet<>();
        if (gameData == null) {
            return set;
        }
        for (List<KowloonBlock> kowloonBlocks : gameData.getBlockList()) {
            for (KowloonBlock block : kowloonBlocks) {
                if (!eKowloonBlockType.isHero(block.getType())) {
                    continue;
                }
                set.add(parsePixel(block.getX()));
            }
        }
        return set;
    }

    /**
     * 随机一下好汉的位置
     * @param heroXPosSet
     * @param posCnt
     * @return
     */
    public static int randomXPos(Set<Integer> heroXPosSet, Map<Integer, Integer> posCnt) {
        Map<Integer, Integer> map = new HashMap<>();
        for (Integer heroXPos : heroXPosSet) {
            map.put(heroXPos, posCnt.getOrDefault(heroXPos, 0));
        }
        int min = Integer.MAX_VALUE;
        List<Integer> list = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            if (entry.getValue() <= min) {
                if (entry.getValue() < min) {
                    min = entry.getValue();
                    list = new ArrayList<>();
                }
                list.add(entry.getKey());
            }
        }
        if (list.size() == 0) {
            return randomHelper.next(0, (int) BATTLE_WIDTH_PIXEL);
        }
        Integer xPos = list.get(randomHelper.next(0, list.size()));
        posCnt.put(xPos, posCnt.getOrDefault(xPos, 0) + 1);
        return xPos;
    }

    /**
     * 计算好汉战斗属性
     */
    private void calcHeroBattleAttribute(SkillInfo moraleSkillInfo) {
        // 加成
        long moraleAddition = 0;
        // 获取当前士气技能
        if (moraleSkillInfo != null) {
            List<Integer> paramList = moraleSkillInfo.getParamList();
            moraleAddition += paramList.get(3);
        }
        // 所有的战斗对象
        for (KowloonBattleHeroData battleHeroData : battleData.getHeroDataList()) {
            KowloonNpcAttributeData attributeData = battleHeroData.getProperty();
            int heroId = battleHeroData.getHeroId();
            // 技能加成
            long addition = moraleAddition + calcAddition(heroId, eSkillType.KowloonSkill182) + calcAddition(heroId, eSkillType.KowloonSkill193);
            attributeData.setAttack(BigDecimal.valueOf(attributeData.getAttack()).multiply(BigDecimal.valueOf(1000 + addition)).divide(BigDecimal.valueOf(1000), 0, RoundingMode.DOWN).longValue());
            // 计算攻速加成
            attributeData.setAtkSpeed(calcAttribute(attributeData.getAtkSpeed(), calcAddition(heroId, eSkillType.KowloonSkill183)).intValue());
            // 计算穿透数量、弹射次数
            attributeData.setAttackNum(attributeData.getAttackNum() + calcAddition(heroId, eSkillType.KowloonSkill185));
            // 减速效果千分比
            attributeData.getSlowBuff().setProbability(calcAttribute(attributeData.getSlowBuff().getProbability(), calcAddition(heroId, eSkillType.KowloonSkill186)).intValue());
            // 冰冻千分比
            attributeData.getFreezeBuff().setProbability(calcAttribute(attributeData.getFreezeBuff().getProbability(), calcAddition(heroId, eSkillType.KowloonSkill187)).intValue());
            // 武器半径
            attributeData.setWeaponRadius(calcAttribute(attributeData.getWeaponRadius(), calcAddition(heroId, eSkillType.KowloonSkill188)).intValue());
            // 提升子弹数
            attributeData.setBullet(attributeData.getBullet() + calcAddition(heroId, eSkillType.KowloonSkill190));
            // 提升加攻范围
            if (attributeData.getAtkBuff().getParam().size() > 0) {
                attributeData.getAtkBuff().getParam().set(0, attributeData.getAtkBuff().getParam().get(0) + calcAddition(heroId, eSkillType.KowloonSkill199));
            }
            // buff叠加
            // 计算额外buff叠加层数
            int addBuffCnt = calcAddition(heroId, eSkillType.KowloonSkill189);
            attributeData.getBleedingBuff().setBuffMaxCount(attributeData.getBleedingBuff().getBuffMaxCount() + addBuffCnt);
            attributeData.getVertigoBuff().setBuffMaxCount(attributeData.getVertigoBuff().getBuffMaxCount() + addBuffCnt);
            attributeData.getFreezeBuff().setBuffMaxCount(attributeData.getFreezeBuff().getBuffMaxCount() + addBuffCnt);
            attributeData.getSlowBuff().setBuffMaxCount(attributeData.getSlowBuff().getBuffMaxCount() + addBuffCnt);
            attributeData.getAtkBuff().setBuffMaxCount(attributeData.getAtkBuff().getBuffMaxCount() + addBuffCnt);
        }

        // 计算琴师加成
        List<KowloonBattleBuffHeroHelper> buffHero1007List = new ArrayList<>();

        // 琴师最大叠加次数
        int buffMaxCount = 0;
        for (KowloonBattleHeroData battleHeroData : battleData.getHeroDataList()) {
            if (battleHeroData.getHeroId() != 1007) {
                continue;
            }
            KowloonNpcConfig heroConfig = config.getKowloonHeroConfig(battleHeroData.getHeroId(), battleHeroData.getLevel(), battleHeroData.getMergeLevel());
            if (heroConfig == null) {
                continue;
            }
            KowloonBattleBuffHeroHelper buffHeroHelper = new KowloonBattleBuffHeroHelper();
            buffHeroHelper.setHeroId(battleHeroData.getHeroId());
            buffHeroHelper.setLevel(battleHeroData.getLevel());
            buffHeroHelper.setMergeLevel(battleHeroData.getMergeLevel());
            buffHeroHelper.setPos(battleHeroData.getPos());
            buffHeroHelper.setBuffRange(heroConfig.getNpcAttribute().getAtkBuffParam().getParam().get(0) + calcAddition(battleHeroData.getHeroId(), eSkillType.KowloonSkill199));
            // 具体加的攻击
            buffHeroHelper.setAddition(BigDecimal.valueOf(battleHeroData.getProperty().getAttack()).multiply(BigDecimal.valueOf(heroConfig.getNpcAttribute().getAtkBuffParam().getProbability())).divide(BigDecimal.valueOf(1000), 0, RoundingMode.DOWN).longValue());
            buffHero1007List.add(buffHeroHelper);

            buffMaxCount = Math.max(buffMaxCount, heroConfig.getNpcAttribute().getAtkBuffParam().getBuffMaxCount());
        }

        // 根据加成降序排个序
        buffHero1007List.sort(Comparator.comparing(KowloonBattleBuffHeroHelper::getAddition).reversed());

        // 上面算完再计算下攻击
        // 所有的战斗对象
        for (KowloonBattleHeroData battleHeroData : battleData.getHeroDataList()) {
            KowloonNpcAttributeData attributeData = battleHeroData.getProperty();
            // 获取琴师buff加成
            attributeData.setAttack(attributeData.getAttack() + calcHero1007Addition(battleHeroData.getPos(), buffHero1007List, buffMaxCount));
        }
    }

    /**
     * 计算琴师加成
     *
     * @param pos              英雄位置
     * @param buffHero1007List 所有琴师位置
     * @param buffMaxCount     最大buff叠加层数
     */
    private long calcHero1007Addition(KowloonCoord pos, List<KowloonBattleBuffHeroHelper> buffHero1007List, int buffMaxCount) {
        long attackAddition = 0;
        int addCnt = 0;
        for (KowloonBattleBuffHeroHelper buffHeroHelper : buffHero1007List) {
            if (addCnt >= buffMaxCount) {
                break;
            }
            // 判断下距离
            double distance = distance(pos, buffHeroHelper.getPos());
            if (distance > buffHeroHelper.getBuffRange()) {
                continue;
            }
            attackAddition += buffHeroHelper.getAddition();
            addCnt++;
        }
        return attackAddition;
    }

    /**
     * 计算两个坐标的距离
     *
     * @param pos1
     * @param pos2
     */
    public double distance(KowloonCoord pos1, KowloonCoord pos2) {
        return Math.sqrt(Math.pow((pos2.getCol() * TILE_SIZE - pos1.getCol() * TILE_SIZE), 2) + Math.pow((pos2.getRow() * TILE_SIZE - pos1.getRow() * TILE_SIZE), 2));
    }

    /**
     * 计算敌人战斗属性
     */
    private void calcEnemyBattleAttribute() {
        for (KowloonBattleEnemyData enemyData : battleData.getEnemyDataList()) {
            KowloonNpcAttributeData attributeData = enemyData.getAttributeData();
            // 降低地痞初始移动速度千分比N4
            attributeData.setMoveSpeed(calcAttribute(attributeData.getMoveSpeed(), -Math.max(0, calcAddition(enemyData.getEnemyId(), eSkillType.KowloonSkill184))).intValue());
        }
    }

    /**
     * 计算属性
     *
     * @param baseValue 基础值
     * @param addRio    加成值
     */
    public BigDecimal calcAttribute(long baseValue, Integer... addRio) {
        int sumAddRio = Arrays.stream(addRio).mapToInt(t -> t).sum();
        return BigDecimal.valueOf(baseValue).multiply(BigDecimal.valueOf(1000 + sumAddRio)).divide(BigDecimal.valueOf(1000), 0, RoundingMode.DOWN);
    }

    /**
     * 计算技能加成
     */
    private int calcAddition(int npcId, eSkillType skillType) {
        int addition = 0;
        for (KowloonSkill skill : gameData.getSkillList()) {
            SkillInfo skillInfo = skillInfoMap.get(skill.getSkillId());
            if (skillInfo == null) {
                continue;
            }
            eSkillType eType = eSkillType.valueOf(skillInfo.getType());
            if (null == eType) {
                continue;
            }
            if (eType != skillType) {
                continue;
            }
            if (skillInfo.getParamList().get(2) != 0 && skillInfo.getParamList().get(2) != npcId) {
                continue;
            }
            // 叠加上限
            int limit = 0;
            if (skillType == eSkillType.KowloonSkill193) {
                if (skillInfo.getParamList().get(1) != 0) {
                    // 加个容错
                    limit = Math.min(skill.getValue() / skillInfo.getParamList().get(1), skillInfo.getMaxLevel());
                }
            } else {
                limit = Math.min(skill.getNum(), skillInfo.getMaxLevel());
            }
            addition += skillInfo.getParamList().get(3) * limit;
        }
        return addition;
    }


    /**
     * 计算移动路线
     *
     * @param enemyData 敌人数据
     */
    private void calcRoute(KowloonBattleEnemyData enemyData) {
        // 是否走到摊位, 判断点位是否y坐标像素是否为0
        while (!enemyData.getWalkRouteList().isEmpty()) {
            // 敌人当前位置
            Vec2 curPos = enemyData.getPath().getLast();
            // 计算下一个拐点
            calcNextPos(enemyData, curPos);
        }
    }

    /**
     * 计算下一个拐点
     *
     * @param curPos 当前位置
     */
    private void calcNextPos(KowloonBattleEnemyData enemyData, Vec2 curPos) {
        Integer walkRoute = enemyData.getWalkRouteList().removeFirst();
        eKowloonRouteType routeType = eKowloonRouteType.forValue(walkRoute);
        if (routeType == null) {
            logger.error("未知路线:{}", walkRoute);
            return;
        }
        Vec2 nextPos = new Vec2();
        switch (routeType) {
            case Route1:
                // 当前点垂直向下走到摊位
                nextPos.setX(curPos.getX());
                nextPos.setY(BOOTH_PIXEL);
                break;
            case Route2:
            case Route8:
                // 当前点走到盘面上一格（盘面上向下走，盘面下向上走）
                int size = gameData.getBlockList().size();
                // 前面1为底格，后面1为盘面上1格
                nextPos.setX(curPos.getX());
                nextPos.setY(parsePixel(1 + size + 1));
                break;
            case Route3:
                // 当前点水平走到一侧（靠左往左走，靠右往右走）
                // 先判断在左侧还是右侧
                if (curPos.getX() <= BATTLE_WIDTH_PIXEL / 2) {
                    // 左
                    nextPos.setX(0 + TILE_SIZE / 2);
                    nextPos.setY(curPos.getY());
                } else {
                    // 右
                    nextPos.setX(BATTLE_WIDTH_PIXEL - TILE_SIZE / 2);
                    nextPos.setY(curPos.getY());
                }
                break;
            case Route4:
                // 当前点水平走到中间（靠左往右走，靠右往左走）
                // 先判断在左侧还是右侧
                if (curPos.getX() <= BATTLE_WIDTH_PIXEL / 2) {
                    // 左
                    nextPos.setX(BATTLE_WIDTH_PIXEL / 2 - TILE_SIZE / 2);
                    nextPos.setY(curPos.getY());
                } else {
                    // 右
                    nextPos.setX(BATTLE_WIDTH_PIXEL / 2 + TILE_SIZE / 2);
                    nextPos.setY(curPos.getY());
                }
                break;
            case Route5:
                // 斜着向上走到另一侧（靠左向右上，靠右向左上）
                // 先判断在左侧还是右侧
                if (curPos.getX() <= BATTLE_WIDTH_PIXEL / 2) {
                    // 左
                    nextPos.setX(BATTLE_WIDTH_PIXEL - TILE_SIZE / 2);
                    nextPos.setY(curPos.getY() + 200);
                } else {
                    // 右
                    nextPos.setX(0 + TILE_SIZE / 2);
                    nextPos.setY(curPos.getY() + 200);
                }
                break;
            case Route6:
                // 斜着向下走到另一侧（靠左向右下，靠右向左下）
                // 先判断在左侧还是右侧
                if (curPos.getX() <= BATTLE_WIDTH_PIXEL / 2) {
                    // 左
                    nextPos.setX(BATTLE_WIDTH_PIXEL - TILE_SIZE / 2);
                    nextPos.setY(curPos.getY() - 200);
                } else {
                    // 右
                    nextPos.setX(0 + TILE_SIZE / 2);
                    nextPos.setY(curPos.getY() - 200);
                }
                break;
            case Route7:
                // 直线闪现
                KowloonNpcConfig enemyConfig = config.getKowloonEnemyConfig(enemyData.getEnemyId());
                // 闪现次数
                int flashCnt = 0;
                // 判断是否还能闪现
                while (flashCnt < enemyConfig.getNpcAttribute().getFlashYPos().size() / 2) {
                    // 随机一个点开始闪现
                    Integer minY = enemyConfig.getNpcAttribute().getFlashYPos().get(flashCnt * 2);
                    Integer maxY = enemyConfig.getNpcAttribute().getFlashYPos().get(flashCnt * 2 + 1);
                    flashCnt++;
                    // 随机出闪现的点
                    int nextY = randomHelper.next(minY, maxY + 1);
                    Vec2 last = enemyData.getPath().getLast();
                    enemyData.getPath().addLast(new Vec2(last.getX(), nextY));
                    // 闪现的点
                    Vec2 flashPos = calcFlashPos(enemyData, enemyData.getPath().getLast());
                    if (flashPos != null) {
                        enemyData.getPath().addLast(flashPos);
                    }
                }
                // 最终点一定是到摊位
                Vec2 last = enemyData.getPath().getLast();
                enemyData.getPath().add(new Vec2(last.getX(), BOOTH_PIXEL));
                // 直接返回
                enemyData.getWalkRouteList().clear();
                return;
            default:
                break;
        }
        // 不会到摊位下面
        nextPos.setY(Math.max(nextPos.getY(), BOOTH_PIXEL));
        // 判断位置是否变化
        if (!nextPos.equals(curPos)) {
            enemyData.getPath().addLast(nextPos);
        }
        // 检测当前位置碰到摊位后续不再走
        if (enemyData.getPath().getLast().getY() <= BOOTH_PIXEL) {
            enemyData.getWalkRouteList().clear();
        }
    }

    private Vec2 calcFlashPos(KowloonBattleEnemyData enemyData, Vec2 curPos) {
        KowloonRange hitRange = enemyData.getAttributeData().getHitRange();
        Vec2 vec2 = new Vec2();
        vec2.setMoveType(1);
        List<int[]> list = new ArrayList<>();
        for (int[] flashDir : FLASH_DIRS) {
            int newX = (int) (curPos.getX() + flashDir[0] * TILE_SIZE);
            int newY = (int) (curPos.getY() + flashDir[1] * TILE_SIZE);
            if (newX < 0 || newX > BATTLE_WIDTH_PIXEL || newY > BATTLE_HEIGHT_PIXEL || newY < 0) {
                continue;
            }
            // 判断下受击范围
            // 左
            int left = newX - hitRange.getWidth() / 2;
            // 右
            int right = newX + hitRange.getWidth() / 2;
            // 上
            int top = newY+hitRange.getHeight() / 2;
            // 下
            int bottom = newY - hitRange.getHeight() / 2;
            // 受击范围超出合成盘面
            if (left < 100 || right > 700 || top > BATTLE_HEIGHT_PIXEL || bottom < 0) {
                continue;
            }
            list.add(flashDir);
        }
        if (list.size() == 0) {
            return null;
        }
        int[] flashDir = list.get(randomHelper.next(0, list.size()));
        vec2.setX((curPos.getX() + flashDir[0] * TILE_SIZE));
        vec2.setY((curPos.getY() + flashDir[1] * TILE_SIZE));
        return vec2;
    }


    /**
     * 坐标转换像素
     * +50 是中心点位置
     */
    private static int parsePixel(int x) {
        return (int) ((x + 1) * TILE_SIZE + TILE_SIZE / 2);
    }

    /**
     * 开始战斗
     */
    public KowloonBattleData battle() {
        KowloonGame game = KowloonGame.getInstance();
        // 这里要拷贝一份出来打,需返回初始数据给客户端
        KowloonBattleData battleDataClone = battleData.clone();
        game.init(battleDataClone);
        game.start();
        // 更新摊位血量
        gameData.setHp(game.getHp());


        // 需要更新返回数据给客户端
        Map<Long, KowloonEnemyDeadParam> deadParamMap = game.getDeadParamMap();
        List<KowloonBattleEnemyData> deadBornEnemyList = new ArrayList<>();
        for (KowloonBattleEnemyData enemyData : battleData.getEnemyDataList()) {
            // 更新路径
            if (!enemyData.getDeadBornEnemyList().isEmpty()) {
                for (KowloonBattleEnemyData battleEnemyData : enemyData.getDeadBornEnemyList()) {
                    if (!deadParamMap.containsKey(battleEnemyData.getUniqueId())) {
                        continue;
                    }
                    KowloonEnemyDeadParam deadParam = deadParamMap.get(battleEnemyData.getUniqueId());
                    battleEnemyData.setBornTime(deadParam.getBornTime());
                    battleEnemyData.setPath(deadParam.getPath());
                    deadBornEnemyList.add(battleEnemyData);
                }
            }
        }
        if (!deadBornEnemyList.isEmpty()) {
            battleData.getEnemyDataList().addAll(deadBornEnemyList);
        }
        // 更新造成的血量
        Map<Long, Integer> hurtDamageMap = game.getHurtDamageMap();
        for (KowloonBattleEnemyData enemyData : battleData.getEnemyDataList()) {
            if (hurtDamageMap.containsKey(enemyData.getUniqueId())) {
                enemyData.setDamage(hurtDamageMap.get(enemyData.getUniqueId()));
            }
        }
        battleData.setWin(isWin());
        return battleData;
    }

    public boolean isWin(){
        return gameData.getHp() > 0;
    }

    public static void main(String[] args) {

    }

}
